package itrace.query.actions;

import iTrace.TechnicalBinding;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.ecore.EObject;

import itrace.query.internal.l10n.QueryStatementsMessages;


import org.eclipse.emf.query.conditions.ObjectInstanceCondition;
import org.eclipse.emf.query.conditions.eobjects.EObjectCondition;
import org.eclipse.emf.query.conditions.eobjects.structuralfeatures.EObjectAttributeValueCondition;

import org.eclipse.emf.query.statements.FROM;
import org.eclipse.emf.query.statements.SELECT;
import org.eclipse.emf.query.statements.WHERE;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.dialogs.ListDialog;

/**
 * This action delegate queries user for the name of a type, then uses the query
 * APIs to find the properties of that type, and select them.
 */
public class Select_TraceLinks_by_TechnicalBinding
	extends AbstractQueryDelegate {

	/**
	 * InputDialog default value
	 */
	private static final TechnicalBinding DEFAULT_VALUE = TechnicalBinding.ATL;

	/**
	 * Constructor
	 */
	public Select_TraceLinks_by_TechnicalBinding() {
		super(QueryStatementsMessages.selectTraceLinks_by_TechnicalBinding_title,
			QueryStatementsMessages.selectTraceLinks_by_TechnicalBinding_inputDialog_message,
			QueryStatementsMessages.selectTraceLinks_by_TechnicalBinding_message_notFound);
	}

	@Override
	protected Collection<EObject> performQuery(Object value)
		throws Exception {
		if (null == selectedEObjects) {
			throw new NullPointerException("Argument 'context' is null"); //$NON-NLS-1$
		}
		if (null == value) {
			throw new NullPointerException("Argument 'value' is null"); //$NON-NLS-1$
		}

		// Get the category
		TechnicalBinding tecBin = (TechnicalBinding)value;
		if (tecBin == null) {
			throw new NullPointerException("Specified Technical Binding is invalid"); //$NON-NLS-1$
		}

		/*
		 * Looking for writers whose authored books of the specified category
		 */
		EObjectCondition condition = new EObjectAttributeValueCondition(
				iTrace.ITracePackage.eINSTANCE
				.getTraceLink_TechnicalBinding(),
				new ObjectInstanceCondition(tecBin));
		

		// Build the select query statement
		SELECT statement = new SELECT(
			new FROM(selectedEObjects), 
			new WHERE(condition)
		);

		// Execute query
		return statement.execute();
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.emf.query.examples.statements.actions.AbstractQueryDelegate#run(org.eclipse.jface.action.IAction)
	 */
	public void run(IAction action) {
		final List<TechnicalBinding> contents = TechnicalBinding.VALUES;
		
		ListDialog dialog = new ListDialog(shell);
		dialog.setTitle(title);
		dialog.setInput(contents);
		dialog.setInitialElementSelections(Collections.singletonList(DEFAULT_VALUE));
		dialog.setContentProvider(new IStructuredContentProvider() {
			public void dispose() {
				// nothing to dispose
			}

			public Object[] getElements(Object inputElement) {
				if (contents != null && contents == inputElement) {
					return contents.toArray();
				}
				return new Object[0];
			}

			public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
				// Do nothing.
			}
		});
		dialog.setLabelProvider(new LabelProvider() {
			@Override
			public String getText(Object element) {
				if (element instanceof Enumerator) {
					return ((Enumerator)element).getName();
				}
				return null;
			}
		});
		dialog.setMessage(QueryStatementsMessages.selectTraceLinks_by_TechnicalBinding_inputDialog_message);
		dialog.setBlockOnOpen(true);
		
		
		if (Window.OK == dialog.open()) {
			try {
				Collection<EObject> result = performQuery(dialog.getResult()[0]);
				if (result.isEmpty()) {
					MessageDialog
						.openInformation(shell, title, notFoundMessage);
				} else {
					this.editor.setSelectionToViewer(result);
				}
			} catch (Exception e) {
				// Exceptions are not expected
				MessageDialog.openInformation(shell, title, MESSAGE_EXCEPTION);
				throw new RuntimeException(e);
			}
		}
	}
	

	@Override
	public void selectionChanged(IAction action, ISelection selection) {
		super.selectionChanged(action, selection);
		
		if (action.isEnabled()) {
			// Ensure that the selection is a selection of library(ies).
			for (EObject o : selectedEObjects) {
				if (!(o instanceof iTrace.iTraceModel)) {
					action.setEnabled(false);
					return;
				}
			}
		}
	}
}